﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Avin.Infrastructure.Linq
{
    public class Queryable<T> : IOrderedQueryable<T>
    {
        private readonly IQueryProvider _provider;

        private readonly Expression _expression;

        Expression IQueryable.Expression
        {
            get { return _expression; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return _provider; }
        }

        public Type ElementType
        {
            get { return typeof(T); }
        }

        public Queryable(QueryProvider provider)
        {
            _provider = provider ?? throw new ArgumentNullException(nameof(provider));
            _expression = Expression.Constant(this);
        }

        internal Queryable(QueryProvider provider, Expression expression)
        {
            if (expression == null)
                throw new ArgumentNullException(nameof(expression));

            if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type))
                throw new ArgumentOutOfRangeException(nameof(expression));


            _provider = provider ?? throw new ArgumentNullException(nameof(provider));
            _expression = expression;
        }

        public IEnumerator<T> GetEnumerator()
        {
            Console.WriteLine("GetEnumerator");

            var provider = (QueryProvider)_provider;
            var result = provider.Execute<T>(_expression);
            if (result == null)
                return new List<T>().GetEnumerator();

            return ((IEnumerable<T>)result).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            Console.WriteLine("IEnumerable.GetEnumerator");

            return ((IEnumerable)_provider.Execute(_expression)).GetEnumerator();
        }
    }
}
